/*
 * safe_queue.h
 *
 *  Created on: Jul 3, 2018
 *      Author: xidian
 */

#ifndef SAFE_QUEUE_H_
#define SAFE_QUEUE_H_
#include <mutex>
#include <condition_variable>
#include <queue>
#include <map>

template<typename T>
class safe_queue
{
private:
	std::mutex				d_mutex;
        std::condition_variable                 d_condition;
        std::queue<T>                           d_queue;
	int 					wait_counter{0};
public:
	void push(T const& value)	{
		{
			std::unique_lock<std::mutex> lock(this->d_mutex);
			d_queue.push(value);
		}
		if(wait_counter>0)
		{
			wait_counter--;
			this->d_condition.notify_one();
		}
	}
	T pop() {
		std::unique_lock<std::mutex> lock(this->d_mutex);
		wait_counter++;
		this->d_condition.wait(lock, [=]{ return !this->d_queue.empty(); });
		T rc(this->d_queue.front());
		this->d_queue.pop();
		return rc;
	}
	bool empty() {
		bool tmp;
		std::unique_lock<std::mutex> lock(this->d_mutex);
		tmp = d_queue.empty();
		return tmp;
	}
	bool try_pop(T &value) {
		std::unique_lock<std::mutex> lock(this->d_mutex);
		if(d_queue.empty())
			return false;
		else
		{
			value = d_queue.front();
			d_queue.pop();
			return true;
		}
	}
	T front() {
		std::unique_lock<std::mutex> lock(this->d_mutex);
		wait_counter++;
		this->d_condition.wait(lock, [=]{return !this->d_queue.empty(); });
		T rc(this->d_queue.front());
		return rc;
	}
	size_t size() {
		size_t tmp;
		{
			std::unique_lock<std::mutex> lock(this->d_mutex);
			tmp = d_queue.size();
		}
		return tmp;
	}
};




#endif /* SRC_TRANSPORT_X64_LINUX_SAFE_QUEUE_H_ */
